using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;

namespace FluentlyXml.Core
{
	public static class ReflectionExtensions
	{
		public static IEnumerable<PropertyInfo> GetPropertiesForSerialization(this Type type)
		{
			return type.GetProperties(BindingFlags.Public | BindingFlags.Instance).Where(p => p.CanRead && p.CanWrite);
		}

		public static PropertyInfo GetProperty<T>(this Expression<Func<T, object>> expression)
		{
			var memberExpression = GetMemberInfo(expression);

			return (PropertyInfo)memberExpression.Member;
		}

		private static MemberExpression GetMemberInfo(Expression method)
		{
			var lambda = method as LambdaExpression;
			
			if (lambda == null)
			{
				throw new ArgumentNullException("method");
			}

			MemberExpression memberExpr = null;

			switch (lambda.Body.NodeType)
			{
				case ExpressionType.Convert:
					memberExpr = ((UnaryExpression)lambda.Body).Operand as MemberExpression;
					break;
				case ExpressionType.MemberAccess:
					memberExpr = lambda.Body as MemberExpression;
					break;
				default:
					throw new ArgumentException("method");
			}

			return memberExpr;
		}

		public static bool IsNullableType(this Type type)
		{
			return type.IsGenericType && type.GetGenericTypeDefinition().Equals(typeof (Nullable<>));
		}
	}
}